﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
using Transforms.Core;
using Transforms.Properties;

namespace Transforms.GUI
{
    public partial class MainForm : Form
    {
        private readonly DataSourceList _sourceList = new DataSourceList();
        private int _nodeCount = -1;
        private int _updateCounter;
        private DataProcessor _outProcessor;

        public MainForm()
        {
            InitializeComponent();

            _sourceList.OnNewItem += (name, item) => AddItem(name, treeViewFiles);

            treeViewFiles.TreeViewNodeSorter = new NodeSorter();

            UpdateCount();
        }

        private void UpdateCount()
        {
            if (InvokeRequired)
                Invoke(new Action(UpdateCount));
            else
            {
                if (_updateCounter > 0) return;

                var count = _sourceList.Count;
                if (_nodeCount != count)
                {
                    _nodeCount = count;
                    toolStripStatusLbl.Text = string.Format("Items: {0}  Size: {1:N0}", _nodeCount, _sourceList.CommonLenth);
                }
            }
        }

        private void AddItem(string name, TreeView treeView)
        {
            if (InvokeRequired)
            {
                Invoke(new Action<string, TreeView>(AddItem), name, treeView);
                return;
            }

            var unEscapeName = Uri.UnescapeDataString(name);
            var folders = unEscapeName.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
            var nodes = treeView.Nodes;
            var i = 0;
            var count = folders.Length - 1;

            foreach (var pathItem in folders)
            {
                if (!nodes.ContainsKey(pathItem))
                {
                    var imageIndex = (i == count) ? 0 : 1;
                    var newNode = nodes.Add(pathItem, pathItem, imageIndex, imageIndex);

                    if (i == count)
                        newNode.Tag = name;
                }

                var node = nodes[pathItem];
                Debug.Assert(node != null);
                nodes = node.Nodes;
                i++;
            }
        }

        private void RecurciveRemove(TreeNode node)
        {
            if (node == null)
                return;

            if (node.Tag != null)
                _sourceList.Remove((string)node.Tag);

            foreach (TreeNode element in node.Nodes)
                RecurciveRemove(element);

            node.Nodes.Clear();
        }

        private void TreeViewFilesDragDrop(object sender, DragEventArgs eventArgs)
        {
            var files = (string[])eventArgs.Data.GetData(DataFormats.FileDrop);

            Func<string, bool> filter = null;

            var history = dtpHistory.Checked ? (DateTime?)dtpHistory.Value : null;
            var extensions = tbxExtensions.Text.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
            if (extensions.Length > 0 || history != null)
                filter = file =>
                                   {
                                       var ext = Path.GetExtension(file);
                                       return extensions.Any(s => s == ext)
                                              && (history == null || new FileInfo(file).LastWriteTime >= history);
                                   };

            var query = files.SelectMany(path => PathSourceFactory.GetFiles(path, filter));

            treeViewFiles.BeginUpdate();
            new Thread(() =>
                           {
                               foreach (var pair in query)
                                   _sourceList.Add(pair.Name, pair.Item);

                               Invoke(new Action(() =>
                                                     {
                                                         treeViewFiles.Sort();
                                                         treeViewFiles.EndUpdate();
                                                     }));

                               UpdateCount();
                           }).Start();
        }

        private void TreeViewFilesDragEnter(object sender, DragEventArgs eventArgs)
        {
            if (_updateCounter > 0)
                eventArgs.Effect = DragDropEffects.None;

            if (eventArgs.Data.GetDataPresent(DataFormats.FileDrop))
                eventArgs.Effect = DragDropEffects.All;
        }

        private void DeleteToolStripMenuItemClick(object sender, EventArgs eventArgs)
        {
            _updateCounter++;
            var node = treeViewFiles.SelectedNode;
            RecurciveRemove(node);

            if (node.Parent == null)
                node.TreeView.Nodes.Remove(node);
            else
                node.Parent.Nodes.Remove(node);

            _updateCounter--;
            UpdateCount();
        }

        private void ContextMenuInFilesOpening(object sender, CancelEventArgs eventArgs)
        {
            eventArgs.Cancel = treeViewFiles.SelectedNode == null;
        }

        private void ButtonBrouseClick(object sender, EventArgs eventArgs)
        {
            var textBox = (sender == btnInBrouse) ? tbxDestination : tbxOutDestination;
            using (
                var dialog = new FolderBrowserDialog { RootFolder = Environment.SpecialFolder.MyComputer, SelectedPath = textBox.Text })
                if (dialog.ShowDialog() == DialogResult.OK)
                    textBox.Text = dialog.SelectedPath;
        }

        private void ButtonRunClick(object sender, EventArgs eventArgs)
        {
            var basis = FileUtils.GetFileDirectoryPath(tbxDestination.Text);
            new DataProcessor().Compile
                 (
                     _sourceList,
                     (int)numPartSize.Value,
                     index => basis + string.Format(tbxPart.Text, index)
                 );

            MessageBox.Show(Resources.MainForm_Done);
        }

        private void ButtonOutBrouseClick(object sender, EventArgs eventArgs)
        {
            using (var dialog = new OpenFileDialog { Multiselect = false })
                if (dialog.ShowDialog() == DialogResult.OK)
                    tbxHeader.Text = dialog.FileName;
        }

        private void BtnReadHeaderClick(object sender, EventArgs eventArgs)
        {
            if (_updateCounter > 0)
                return;

            _outProcessor = new DataProcessor();

            _updateCounter++;
            try
            {
                new Thread(() => _outProcessor.ReadHeader(tbxHeader.Text, name => AddItem(name, treeViewOutFiles))).Start();
            }
            finally
            {
                // TODO: Error -> it runs in thread
                _updateCounter--;
            }
        }

        private void BtnExtractClick(object sender, EventArgs eventArgs)
        {
            _outProcessor.Extract(tbxOutDestination.Text);
            MessageBox.Show(Resources.MainForm_Done);
        }

        #region Nested type: NodeSorter

        private class NodeSorter : IComparer
        {
            #region IComparer Members

            public int Compare(object nodeA, object nodeB)
            {
                var treeNodeA = nodeA as TreeNode;
                var treeNodeB = nodeB as TreeNode;

                if (treeNodeA == null)
                    return -1;

                if (treeNodeB == null)
                    return 1;

                if (treeNodeA.Nodes.Count == treeNodeB.Nodes.Count)
                    return string.Compare(treeNodeA.Text, treeNodeB.Text, StringComparison.InvariantCultureIgnoreCase);

                return (treeNodeA.Nodes.Count > treeNodeB.Nodes.Count) ? -1 : 1;
            }

            #endregion
        }

        #endregion
    }
}